package maa.dao.h2;

import maa.dao.DAOException;
import maa.dao.DAOManager;
import maa.dao.DAOCommand;
import maa.dao.UserDAO;
import maa.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class UserDAOimpl implements DAOCommand, UserDAO {
    private static final Logger logger = LoggerFactory.getLogger(UserDAOimpl.class);
    private static final String UPDATE_USER = "UPDATE users SET username =?, surname = ?,email =?,password=?," +
            " birthdate = ?, gender =? where userid=?";
    private static final String SWITCH_ROLE_TO_CLIENT = "UPDATE users SET role='CLIENT' where userid=?";
    private final String CREATE_USER = "INSERT INTO users(userid, email, password, username, " +
            "surname, birthdate, gender, role) VALUES(?, ?, ?, ?, ?, ?, ?, ?)";
    private final String FIND_BY_EMAIL_PASSWORD = "SELECT * FROM users WHERE users.email = ? AND users.password = ?";
    private final String FIND_ALL = "SELECT * FROM USERS where role = ?";
    private final String DELETE_USER = "DELETE from users where userid = ?";
    private final String FIND_BY_ID = "SELECT * FROM USERS WHERE USERID = ?";
    private final String SWITCH_ROLE_TO_MENTOR = "UPDATE users SET role='MENTOR' where userid=?";

    private Connection connection;

    public UserDAOimpl() {

    }

    public UserDAOimpl(Connection connection) {
        this.connection = connection;
    }

    public boolean switchRoleToMentor(UUID uuid) throws DAOException {
        int res = 0;
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(SWITCH_ROLE_TO_MENTOR);
                preparedStatement.setObject(1, uuid);
                res = preparedStatement.executeUpdate();
            } catch (SQLException e) {
                logger.error("Could not switch role to mentor " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        if (res > 0) {
            logger.debug("Switched user's" + uuid.toString() + "role from CLIENT to MENTOR");
            return true;
        } else {
            logger.debug("Failed to switch user's" + uuid.toString() + "role from CLIENT to MENTOR of user");
            return false;
        }
    }

    public boolean switchRoleToClient(UUID uuid) throws DAOException {
        int res = 0;
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(SWITCH_ROLE_TO_CLIENT);
                preparedStatement.setObject(1, uuid);
                res = preparedStatement.executeUpdate();
            } catch (SQLException e) {
                logger.error("Could not switch role to client " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        if (res > 0) {
            logger.debug("Switched user's" + uuid.toString() + "role from MENTOR to CLIENT");
            return true;
        } else {
            logger.debug("Failed to switch user's" + uuid.toString() + "role from MENTOR to CLIENT of user");
            return false;
        }
    }

    public boolean delete(UUID uuid) throws DAOException {
        int res = 0;
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(DELETE_USER);
                preparedStatement.setObject(1, uuid);
                res = preparedStatement.executeUpdate();

            } catch (SQLException e) {
                logger.error("Could not delete user " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        if (res > 0) {
            logger.debug("Deleted user with id: " + uuid.toString());
            return true;
        } else {
            logger.debug("Failed to delete user with id: " + uuid.toString());
            return false;
        }

    }

    public List<User> findAll() throws DAOException {
        List<User> list = new ArrayList<>();
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(FIND_ALL);
                preparedStatement.setString(1, "CLIENT");
                ResultSet set = preparedStatement.executeQuery();
                while (set.next()) {
                    User user = createEntity(set);
                    list.add(user);
                }
            } catch (SQLException e) {
                logger.error("Could not find all users " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        logger.debug("Extracted all clients from database");
        return list;
    }

    public User findByEmailAndPassword(String email, String password) throws DAOException {
        User user = new User();
        if (connection != null && email != null && password != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(FIND_BY_EMAIL_PASSWORD);
                preparedStatement.setString(1, email);
                preparedStatement.setString(2, password);
                ResultSet resultSet = preparedStatement.executeQuery();
                if (resultSet.next()) {
                    user = createEntity(resultSet);
                }
            } catch (SQLException e) {
                logger.error("Could not find user by email and password " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        logger.debug("Extracted user: " + user.toString());
        return user;
    }

    public User findById(UUID uuid) throws DAOException {
        User user = new User();
        if (connection != null && uuid != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(FIND_BY_ID);
                preparedStatement.setObject(1, uuid);
                ResultSet resultSet = preparedStatement.executeQuery();
                if (resultSet.next()) {
                    user = createEntity(resultSet);
                }
            } catch (SQLException e) {
                logger.error("Could not find user by id " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        return user;
    }

    public List<User> findUsersById(List<UUID> uuids) throws DAOException {
        List<User> users = new ArrayList<>();
        for (UUID uuid : uuids) {
            users.add(findById(uuid));
        }
        return users;
    }

    public boolean create(User user) throws DAOException {
        int res = 0;
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            UUID userID = UUID.randomUUID();
            try {
                preparedStatement = connection.prepareStatement(CREATE_USER);
                preparedStatement.setObject(1, user.getUuid());
                preparedStatement.setString(2, user.getEmail());
                preparedStatement.setString(3, user.getPassword());
                preparedStatement.setString(4, user.getName());
                preparedStatement.setString(5, user.getSurname());
                preparedStatement.setDate(6, user.getBirthdate());
                preparedStatement.setString(7, String.valueOf(user.getGender()));
                preparedStatement.setString(8, String.valueOf(user.getRole()));

                res = preparedStatement.executeUpdate();

            } catch (SQLException e) {
                logger.error(e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        if (res > 0) return true;
        else return false;
    }

    public User createEntity(ResultSet resultSet) throws SQLException {
        User user = new User();
        user.setUuid((UUID) resultSet.getObject("userid"));
        user.setName(resultSet.getString("username"));
        user.setSurname(resultSet.getString("surname"));
        user.setRole(Role.valueOf(resultSet.getString("role")));
        user.setGender(Gender.valueOf(resultSet.getString("gender")));
        user.setBirthdate(resultSet.getDate("birthdate"));
        user.setEmail(resultSet.getString("email"));
        user.setPassword(resultSet.getString("password"));
        return user;
    }

    @Override
    public Object execute(DAOManager daoManager) {
        return new Object();
    }

    public Boolean update(User user) throws DAOException {
        int res = 0;
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            try {
                preparedStatement = connection.prepareStatement(UPDATE_USER);
                preparedStatement.setString(1, user.getName());
                preparedStatement.setString(2, user.getSurname());
                preparedStatement.setString(3, user.getEmail());
                preparedStatement.setString(4, user.getPassword());
                preparedStatement.setDate(5, user.getBirthdate());
                preparedStatement.setString(6, String.valueOf(user.getGender()));
                preparedStatement.setObject(7, user.getUuid());

                res = preparedStatement.executeUpdate();
            } catch (SQLException e) {
                logger.error("Could not update user " + e.getMessage());
                throw new DAOException(e.getMessage());
            } finally {
                if (preparedStatement != null) {
                    close(preparedStatement);
                }
            }
        } else {
            throw new DAOException("No connection available");
        }
        if (res > 0) return true;
        else return false;
    }

    public void close(PreparedStatement statement) {
        try {
            statement.close();
        } catch (SQLException e) {
            logger.error(e.getMessage());
        }
    }
}
